package com.flyqiu.common.mybaits.plus;


import com.baomidou.mybatisplus.annotation.TableField;
import com.flyqiu.common.clazz.FlyQiuFieldFilter;
import com.flyqiu.common.mybaits.plus.enums.FlyQiuQueryCondition;
import com.flyqiu.common.mybaits.plus.properties.FlyQiuEntityQueryProperty;
import com.flyqiu.common.property.FlyQiuPropertyTools;
import com.flyqiu.common.tools.FlyQiuCollectionTools;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

public class FlyQiuEntityQuery<T> extends AbstractCommonQuery<T> {

    /**
     * 对象指端缓存
     */
    private static final Map<Class<?>, List<FlyQiuEntityQueryProperty>> objectCache = new ConcurrentHashMap<>();

    private final Class<T> entityClazz;

    @SuppressWarnings("unused")
    public Class<T> getEntityClazz() {
        return entityClazz;
    }


    private List<FlyQiuEntityQueryProperty> queryEntityProperties = new ArrayList<>();

    public FlyQiuEntityQuery(T entity, Map<String, ?> parameterMap) {
        if (entity == null) throw new RuntimeException("T entity not null");
        //noinspection unchecked
        entityClazz = (Class<T>) entity.getClass();
        init(parameterMap);
    }

    public FlyQiuEntityQuery(Class<T> clazz, Map<String, ?> parameterMap) {
        if (clazz == null) throw new RuntimeException("clazz cannot be  null");
        this.entityClazz = clazz;
        init(parameterMap);
    }

    private void init(Map<String, ?> map) {
        if (map == null) {
            map = new HashMap<>();
        }
        FlyQiuCollectionTools.iterator(map, (key, object) -> parameterMap.put(key, String.valueOf(object)));
        queryEntityProperties = getClassQueryProperties();
    }


    /**
     * 解析实体查询条件
     */
    @Override
    public void analysisSearchQuery(String prefix) {
        String fieldVal;
        String key;
        QueryRuleModel ruleModel;
        for (FlyQiuEntityQueryProperty field : queryEntityProperties) {
            key = prefix + field.getName();
            if (!parameterMap.containsKey(key)) continue;
            fieldVal = parameterMap.get(key);
            if (StringUtils.isBlank(fieldVal)) continue;
            ruleModel = FlyQiuQueryCondition.getRuleCondition(fieldVal);
            ruleModel.setColName(field.getColName());
            constructorCondition(ruleModel);
        }
    }


    @Override
    public void analysisQueryOrder(String prefix) {
        QueryRuleModel ruleModel = null;
        String key;
        for (FlyQiuEntityQueryProperty field : queryEntityProperties) {
            key = prefix + field.getName();
            if (!parameterMap.containsKey(key)) continue;
            String values = parameterMap.get(key);
            if (StringUtils.isBlank(values)) continue;
            FlyQiuQueryCondition conditionEnum = FlyQiuQueryCondition.ORDER_BY_ASC;
            if (values.trim().equalsIgnoreCase("desc")) {
                conditionEnum = FlyQiuQueryCondition.ORDER_BY_DESC;
            }
            ruleModel = new QueryRuleModel();
            ruleModel.setCondition(conditionEnum);
            ruleModel.setColName(field.getColName());
            constructorCondition(ruleModel);
        }
    }


    @Override
    public boolean enableHumpNaming() {
        return true;
    }


    public List<FlyQiuEntityQueryProperty> getClassQueryProperties() {
        if (!objectCache.containsKey(entityClazz)) {
            analysisObject(entityClazz);
        }
        return objectCache.get(entityClazz);
    }

    private void analysisObject(Class<T> clazz) {
        if (objectCache.containsKey(clazz)) return;
        boolean enableHumpNaming = enableHumpNaming();
        FlyQiuFieldFilter filter = (field, clazz1) -> {
            TableField annotation = field.getAnnotation(TableField.class);
            if (annotation == null) {
                return true;
            }
            return annotation.exist();
        };

        Function<Field, FlyQiuEntityQueryProperty> valMapper = field -> new FlyQiuEntityQueryProperty(field, enableHumpNaming);
        List<FlyQiuEntityQueryProperty> properties = FlyQiuPropertyTools.getProperties(clazz, filter, valMapper);
        objectCache.put(clazz, properties);
    }

}
